-
Notifications
You must be signed in to change notification settings - Fork 58
Don't replay events when all matches have only keyup suffixes #205
Conversation
First, thanks for diving into this complex issue. Unfortunately I'm seeing the same behavior you describe in #190 even using this code. I will keep digging because I'd like to better understand what's going on here but I likely won't get to it until next week. It's almost certainly a weird interaction with the recent changes to better support international keyboards.
No disagreement here! Unfortunately this same complexity makes it a significant effort and high risk to rewrite.
I think I don't understand this. The only keyup binding that ships in a default install of Atom now is for MRU tab traversal:
So when a user presses
I actually experimented with a set of validations very much like this one recently. In the end it was a ton of complexity for dubious gain: it's possible to add all kinds of keybindings that can lead to bizarre behavior within the app. There's not a clear benefit to attempting to prevent this particular subset.
I believe this is actually an accurate description of the current behavior. Pending keyup matches get stashed in pendingKeyupMatcher. When there's a keyup event it updates its state and returns matches. I'll stop here for now and see if we can come to a better common understanding via a couple more comment roundtrips. :) Again, I do really appreciate your taking the time to dive into some super gnarly code. More from me next week. |
My mistake; the example in #190 failed for me too -- I was testing that the tab-switcher example worked (where the focus moves to another element on keydown). I've added another commit which fixes both.
The distinction I was trying to make between the current & proposed behavior is we just wait until foo is released, as opposed to treating "^foo" as a full-fledged keystroke that could be surrounded by other keyup and keydown events in the binding. It sounds like you would agree that this is sufficient.
Thanks for the pointers; I had indeed overlooked the What I'm thinking is that for a binding like "alt-a ^alt", everything could happen when alt-a is pressed except the actual command dispatch and emit() call, which is delayed until alt is released. And everything except those two things could be skipped for the keyup event. This would mean the keystrokes are removed from the queued keystrokes on keydown too.
I can see adding validations as adding complexity, but all I'm proposing is that scenarios outside these cases be considered undefined behavior -- that is, we shouldn't worry about changing the behavior for these unlikely cases in order to simplify things internally. (I actually would favor showing a warning if bindings include anything considered UB, but agree there is a complexity tradeoff.) |
There is a legitimate bug here but since we agree this PR doesn't resolve it, I'm going to close it. |
@iolsen I believe this PR does solve the current problems. (First paragraph of my last comment: "I've added another commit which fixes both.") Any thoughts on this fix? |
🤦♂️ sorry I missed that. I'll take a look! |
@iolsen did you get a chance to take a look at this? |
@oggy so sorry for the delay. I haven't looked at this yet but should have time in the next few weeks. |
This problem is no longer happening as of 1.19 or 1.21-dev. |
I believe this fixes #190, in which I found that binding a command to
alt-[
caused an errant "alt-character" to get inserted (MacOS + U.S keyboard layout) if alt is held down for a second.The problem is that when
alt-[
is pressed, the timeout is triggered, with thealt-[
left on the list of queued keys. When the timeout fires, the keys are replayed with the binding added to@bindingsToDisable
, which is why the U+201C gets inserted. (Or if you have a 2nd command bound toalt-[
it'll fire that instead). This problem is not specific to thealt
key, but is most noticeable due to all the built-in Mac OS alt- key combos serving as shadowed bindings.cc @iolsen
Alternate Designs
I strove to keep this change as small as possible in the interest of fixing my immediate problem sooner.
However, I do find the complexity of the key handling algorithm uncomfortably complex, and I think it's largely due to the keyup semantics. I'm wondering: how would you feel about simplifying it so that instead of thinking of the keyup (
^foo
) as an event in the binding sequence, it's more like an annotation that just means "... and wait until foo is released." Which I'm hoping is sufficient for all real use cases.More formally I'd propose:
This would let us completely divorce the keyup handling from the keydown. i.e.:
The last bullet above also removes some ugliness in the case where you want the keydown to give focus to another element until the keyup fires. I've run into this making the tab-switcher plugin, where one often wants to override the built-in ctrl-tab keys, but the keydown gives focus to separate "tab list" element. To achieve the right result you need:
This is a little confusing & ugly -- more intuitive to me would be:
Thoughts about this idea? Happy to have a go at implementing it, but wanted to get your feedback first.
Benefits
Fixes #190.
Possible Drawbacks
None.
Applicable Issues
None.